package cn.simple.filetools.poi.excel.support;

import cn.simple.filetools.annotation.Excels;
import cn.simple.filetools.enums.OperateType;
import cn.simple.filetools.exception.NoAnnotationException;
import cn.simple.filetools.exception.PermissionErrorException;
import cn.simple.filetools.exception.ReadExcelException;
import cn.simple.filetools.poi.excel.PoiExcelWriteProcessor;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.ByteArrayOutputStream;
import java.io.OutputStream;
import java.util.List;

/**
 * @author jiangjinjian
 * @date 2024/8/28 9:20
 * @description 抽象poi-excel写出处理器
 */
@Getter
@Slf4j
public abstract class AbstractPoiExcelWriteProcessor<T> implements PoiExcelWriteProcessor<T> {

    @Override
    public OutputStream write(List<T> data) {
        Class<T> targetClass = (Class<T>) data.get(0).getClass();
        try (XSSFWorkbook wb = new XSSFWorkbook()) {
            //创建sheet
            XSSFSheet sheet = createSheet(wb);
            Excels excels = targetClass.getAnnotation(Excels.class);
            if (excels == null) {
                throw new NoAnnotationException(String.format("类[%s]缺少[Excels]注解", targetClass.getTypeName()));
            }
            if (!OperateType.EXPORT_OPERATE_LIST.contains(excels.operateType())) {
                throw new PermissionErrorException(String.format("类[%s]没有导出的权限", targetClass.getTypeName()));
            }
            for (int i = 0; i <= data.size(); i++) {
                //创建行
                XSSFRow row = sheet.createRow(i);
                if (i == 0) {
                    writeHead(targetClass, row);
                } else {
                    //渲染行数据
                    writeRow(data.get(i-1), row, sheet);
                }
            }
            ByteArrayOutputStream os = new ByteArrayOutputStream();
            wb.write(os);
            return os;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new ReadExcelException(e);
        }
    }

    /**
     * 创建sheet
     *
     * @param wb 工作簿
     * @return
     */
    protected abstract XSSFSheet createSheet(XSSFWorkbook wb);

    /**
     * 渲染行数据
     *
     * @param data  对象数据
     * @param row   当前行
     * @param sheet 当前sheet
     */
    protected abstract void writeRow(T data, Row row, Sheet sheet);

    /**
     * 编写表头
     *
     * @param tClass 类
     * @param row    当前行
     */
    protected abstract void writeHead(Class<T> tClass, Row row);

}
